/*-------------------------------------------------------------------------
 *
 * llvmjit.c
 *	  LLVM JIT提供者的核心部分。
 *
 * Copyright (c) 2016-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/backend/jit/llvm/llvmjit.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <llvm-c/Analysis.h>
#include <llvm-c/BitReader.h>
#include <llvm-c/BitWriter.h>
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#if LLVM_VERSION_MAJOR > 16
#include <llvm-c/Transforms/PassBuilder.h>
#endif
#if LLVM_VERSION_MAJOR > 11
#include <llvm-c/Orc.h>
#include <llvm-c/OrcEE.h>
#include <llvm-c/LLJIT.h>
#else
#include <llvm-c/OrcBindings.h>
#endif
#include <llvm-c/Support.h>
#include <llvm-c/Target.h>
#if LLVM_VERSION_MAJOR < 17
#include <llvm-c/Transforms/IPO.h>
#include <llvm-c/Transforms/PassManagerBuilder.h>
#include <llvm-c/Transforms/Scalar.h>
#if LLVM_VERSION_MAJOR > 6
#include <llvm-c/Transforms/Utils.h>
#endif
#endif

#include "jit/llvmjit.h"
#include "jit/llvmjit_backport.h"
#include "jit/llvmjit_emit.h"
#include "miscadmin.h"
#include "portability/instr_time.h"
#include "storage/ipc.h"
#include "utils/memutils.h"
#include "utils/resowner_private.h"

#define LLVMJIT_LLVM_CONTEXT_REUSE_MAX 100

/* 通过 ORC JIT 发出的模块的句柄 */
typedef struct LLVMJitHandle
{
#if LLVM_VERSION_MAJOR > 11
	LLVMOrcLLJITRef lljit;
	LLVMOrcResourceTrackerRef resource_tracker;
#else
	LLVMOrcJITStackRef stack;
	LLVMOrcModuleHandle orc_handle;
#endif
} LLVMJitHandle;


/* JIT 编程常用的类型和函数 */
LLVMTypeRef TypeSizeT;
LLVMTypeRef TypeParamBool;
LLVMTypeRef TypeStorageBool;
LLVMTypeRef TypePGFunction;
LLVMTypeRef StructNullableDatum;
LLVMTypeRef StructHeapTupleFieldsField3;
LLVMTypeRef StructHeapTupleFields;
LLVMTypeRef StructHeapTupleHeaderData;
LLVMTypeRef StructHeapTupleDataChoice;
LLVMTypeRef StructHeapTupleData;
LLVMTypeRef StructMinimalTupleData;
LLVMTypeRef StructItemPointerData;
LLVMTypeRef StructBlockId;
LLVMTypeRef StructFormPgAttribute;
LLVMTypeRef StructTupleConstr;
LLVMTypeRef StructTupleDescData;
LLVMTypeRef StructTupleTableSlot;
LLVMTypeRef StructHeapTupleTableSlot;
LLVMTypeRef StructMinimalTupleTableSlot;
LLVMTypeRef StructMemoryContextData;
LLVMTypeRef StructPGFinfoRecord;
LLVMTypeRef StructFmgrInfo;
LLVMTypeRef StructFunctionCallInfoData;
LLVMTypeRef StructExprContext;
LLVMTypeRef StructExprEvalStep;
LLVMTypeRef StructExprState;
LLVMTypeRef StructAggState;
LLVMTypeRef StructAggStatePerGroupData;
LLVMTypeRef StructAggStatePerTransData;
LLVMTypeRef StructPlanState;

LLVMValueRef AttributeTemplate;
LLVMValueRef ExecEvalSubroutineTemplate;
LLVMValueRef ExecEvalBoolSubroutineTemplate;

LLVMModuleRef llvm_types_module = NULL;

static bool llvm_session_initialized = false;
static size_t llvm_generation = 0;

/* 当前使用的 LLVMJitContexts 的数量 */
static size_t llvm_jit_context_in_use_count = 0;

/* 当前的 LLVMContextRef 被使用的次数 */
static size_t llvm_llvm_context_reuse_count = 0;
static const char *llvm_triple = NULL;
static const char *llvm_layout = NULL;
static LLVMContextRef llvm_context;


static LLVMTargetRef llvm_targetref;
#if LLVM_VERSION_MAJOR > 11
static LLVMOrcThreadSafeContextRef llvm_ts_context;
static LLVMOrcLLJITRef llvm_opt0_orc;
static LLVMOrcLLJITRef llvm_opt3_orc;
#else							/* LLVM_VERSION_MAJOR > 11 */
static LLVMOrcJITStackRef llvm_opt0_orc;
static LLVMOrcJITStackRef llvm_opt3_orc;
#endif							/* LLVM_VERSION_MAJOR > 11 */


static void fc_llvm_release_context(JitContext *fc_context);
static void fc_llvm_session_initialize(void);
static void fc_llvm_shutdown(int fc_code, Datum fc_arg);
static void fc_llvm_compile_module(LLVMJitContext *fc_context);
static void fc_llvm_optimize_module(LLVMJitContext *fc_context, LLVMModuleRef fc_module);

static void fc_llvm_create_types(void);
static void fc_llvm_set_target(void);
static void fc_llvm_recreate_llvm_context(void);
static uint64_t fc_llvm_resolve_symbol(const char *fc_name, void *fc_ctx);

#if LLVM_VERSION_MAJOR > 11
static LLVMOrcLLJITRef fc_llvm_create_jit_instance(LLVMTargetMachineRef fc_tm);
static char *fc_llvm_error_message(LLVMErrorRef fc_error);
#endif							/* LLVM_VERSION_MAJOR > 11 */

PG_MODULE_MAGIC;


/* 初始化 LLVM JIT 提供程序。 */
void _PG_jit_provider_init(JitProviderCallbacks *fc_cb)
{
	fc_cb->reset_after_error = llvm_reset_after_error;
	fc_cb->release_context = fc_llvm_release_context;
	fc_cb->compile_expr = llvm_compile_expr;
}


/* 不时创建一个新的 LLVMContextRef。不幸的是，在每轮内联中，类型可能会“泄漏”（它们仍然可以通过上下文找到/使用，但下一次内联时将创建新类型）。为了防止这导致逐渐累积的问题内存，重新创建我们使用的 LLVMContextRef。我们不想过于频繁地这样做，因为这意味着一些开销（特别是重新加载模块摘要/模块是相当昂贵的）。未来的 TODO 是使其更细粒度，仅在我们知道有内联时丢弃/重新创建 LLVMContextRef。如果我们能够从 LLVM 获取上下文的大小，那么这可能是更好的决定何时丢弃/重新创建的方式，而不是当前使用的使用计数启发式。 */
static void fc_llvm_recreate_llvm_context(void)
{
	if (!llvm_context)
		elog(ERROR, "Trying to recreate a non-existing context");

	/* 只有在没有其他代码被 JIT 编译的情况下，我们才能安全地重新创建 LLVM 上下文，否则我们会释放正在使用的类型。 */
	if (llvm_jit_context_in_use_count > 0)
	{
		llvm_llvm_context_reuse_count++;
		return;
	}

	if (llvm_llvm_context_reuse_count <= LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
	{
		llvm_llvm_context_reuse_count++;
		return;
	}

	/* 在处理上下文之前，需要重置内联代码缓存的模块。LLVM 模块存在于特定的 LLVM 上下文中，因此在重置缓存之前处置上下文会导致对模块的悬挂指针。 */
	llvm_inline_reset_caches();

	LLVMContextDispose(llvm_context);
	llvm_context = LLVMContextCreate();
	llvm_llvm_context_reuse_count = 0;

	/* 重新构建缓存的类型信息，以便代码生成代码可以依赖该信息的存在（还可以防止变量成为悬挂引用）。 */
	fc_llvm_create_types();
}


/* 创建用于 JIT 工作的上下文。 * 上下文及其附属资源将在上下文被显式释放时或当 CurrentResourceOwner 的生存期结束时（通常是当前 [子] 事务的结束时）进行清理。 */
LLVMJitContext *
llvm_create_context(int fc_jitFlags)
{
	LLVMJitContext *fc_context;

	llvm_assert_in_fatal_section();

	fc_llvm_session_initialize();

	fc_llvm_recreate_llvm_context();

	ResourceOwnerEnlargeJIT(CurrentResourceOwner);

	fc_context = MemoryContextAllocZero(TopMemoryContext,
									 sizeof(LLVMJitContext));
	fc_context->base.flags = fc_jitFlags;

	/* 确保清理 */
	fc_context->base.resowner = CurrentResourceOwner;
	ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(fc_context));

	llvm_jit_context_in_use_count++;

	return fc_context;
}

/* 释放一个 llvm 上下文所需的资源。 */
static void fc_llvm_release_context(JitContext *fc_context)
{
	LLVMJitContext *fc_llvm_jit_context = (LLVMJitContext *) fc_context;
	ListCell   *fc_lc;

	/* 即使我们在下面跳过清理，也将其视为已清理，这样我们可以验证跟踪是正确的（见 llvm_shutdown()）。 */
	llvm_jit_context_in_use_count--;

	/* 当这个后端退出时，不要清理 LLVM。由于可能在 LLVM 内部发生了错误，我们不想冒险重新进入。所有资源清理将在进程退出时发生。 */
	if (proc_exit_inprogress)
		return;

	llvm_enter_fatal_on_oom();

	if (fc_llvm_jit_context->module)
	{
		LLVMDisposeModule(fc_llvm_jit_context->module);
		fc_llvm_jit_context->module = NULL;
	}

	foreach(fc_lc, fc_llvm_jit_context->handles)
	{
		LLVMJitHandle *fc_jit_handle = (LLVMJitHandle *) lfirst(fc_lc);

#if LLVM_VERSION_MAJOR > 11
		{
			LLVMOrcExecutionSessionRef fc_ee;
			LLVMOrcSymbolStringPoolRef fc_sp;

			LLVMOrcResourceTrackerRemove(fc_jit_handle->resource_tracker);
			LLVMOrcReleaseResourceTracker(fc_jit_handle->resource_tracker);

			/* 在不触发字符串池的清理的情况下，我们会泄漏内存。这样做较少的频率就足够了，但在实验中所需的时间小到可以始终执行这一操作。 */
			fc_ee = LLVMOrcLLJITGetExecutionSession(fc_jit_handle->lljit);
			fc_sp = LLVMOrcExecutionSessionGetSymbolStringPool(fc_ee);
			LLVMOrcSymbolStringPoolClearDeadEntries(fc_sp);
		}
#else							/* LLVM_VERSION_MAJOR > 11 */
		{
			LLVMOrcRemoveModule(jit_handle->stack, jit_handle->orc_handle);
		}
#endif							/* LLVM_VERSION_MAJOR > 11 */

		pfree(fc_jit_handle);
	}
	list_free(fc_llvm_jit_context->handles);
	fc_llvm_jit_context->handles = NIL;

	llvm_leave_fatal_on_oom();
}

/* 返回可以修改的模块，例如，创建新函数。 */
LLVMModuleRef
llvm_mutable_module(LLVMJitContext *fc_context)
{
	llvm_assert_in_fatal_section();

	/* 如果没有正在进行的模块，创建一个新的。 */
	if (!fc_context->module)
	{
		fc_context->compiled = false;
		fc_context->module_generation = llvm_generation++;
		fc_context->module = LLVMModuleCreateWithNameInContext("pg", llvm_context);
		LLVMSetTarget(fc_context->module, llvm_triple);
		LLVMSetDataLayout(fc_context->module, llvm_layout);
	}

	return fc_context->module;
}

/* 扩展函数名以避免冲突。这应该由代码生成代码使用，当向模块添加新的外部可见函数定义时。 */
char * llvm_expand_funcname(struct LLVMJitContext *fc_context, const char *fc_basename)
{
	Assert(fc_context->module != NULL);

	fc_context->base.instr.created_functions++;

	/* 之前我们使用点来分隔，但事实证明某些工具，例如 GDB，不喜欢这样并截断名称。 */
	return psprintf("%s_%zu_%d",
					fc_basename,
					fc_context->module_generation,
					fc_context->counter++);
}

/* 返回指向必须存在的函数 funcname 的指针。如果有待优化和发出的代码，首先执行此操作。 */
void * llvm_get_function(LLVMJitContext *fc_context, const char *fc_funcname)
{
#if LLVM_VERSION_MAJOR > 11 || \
	defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
	ListCell   *fc_lc;
#endif

	llvm_assert_in_fatal_section();

	/* 如果有待处理/未发出的模块，则立即编译并发出。否则我们可能找不到 [正确的] 函数。 */
	if (!fc_context->compiled)
	{
		fc_llvm_compile_module(fc_context);
	}

	/* ORC 的符号表是 *未被篡改* 的符号。因此我们在这里不需要篡改。 */

#if LLVM_VERSION_MAJOR > 11
	foreach(fc_lc, fc_context->handles)
	{
		LLVMJitHandle *fc_handle = (LLVMJitHandle *) lfirst(fc_lc);
		instr_time	fc_starttime;
		instr_time	fc_endtime;
		LLVMErrorRef fc_error;
		LLVMOrcJITTargetAddress fc_addr;

		INSTR_TIME_SET_CURRENT(fc_starttime);

		fc_addr = 0;
		fc_error = LLVMOrcLLJITLookup(fc_handle->lljit, &fc_addr, fc_funcname);
		if (fc_error)
			elog(ERROR, "failed to look up symbol \"%s\": %s",
				 fc_funcname, fc_llvm_error_message(fc_error));

		/* LLJIT 只有在第一次引用符号时才实际发出代码。因此将查找时间添加到发出时间。这比旧版本的 LLVM 计算得多，但不太可能有任何问题。 */
		INSTR_TIME_SET_CURRENT(fc_endtime);
		INSTR_TIME_ACCUM_DIFF(fc_context->base.instr.emission_counter,
							  fc_endtime, fc_starttime);

		if (fc_addr)
			return (void *) (uintptr_t) fc_addr;
	}
#elif defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
	foreach(lc, context->handles)
	{
		LLVMOrcTargetAddress addr;
		LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc);

		addr = 0;
		if (LLVMOrcGetSymbolAddressIn(handle->stack, &addr, handle->orc_handle, funcname))
			elog(ERROR, "failed to look up symbol \"%s\"", funcname);
		if (addr)
			return (void *) (uintptr_t) addr;
	}
#elif LLVM_VERSION_MAJOR < 5
	{
		LLVMOrcTargetAddress addr;

		if ((addr = LLVMOrcGetSymbolAddress(llvm_opt0_orc, funcname)))
			return (void *) (uintptr_t) addr;
		if ((addr = LLVMOrcGetSymbolAddress(llvm_opt3_orc, funcname)))
			return (void *) (uintptr_t) addr;
	}
#else
	{
		LLVMOrcTargetAddress addr;

		if (LLVMOrcGetSymbolAddress(llvm_opt0_orc, &addr, funcname))
			elog(ERROR, "failed to look up symbol \"%s\"", funcname);
		if (addr)
			return (void *) (uintptr_t) addr;
		if (LLVMOrcGetSymbolAddress(llvm_opt3_orc, &addr, funcname))
			elog(ERROR, "failed to look up symbol \"%s\"", funcname);
		if (addr)
			return (void *) (uintptr_t) addr;
	}
#endif

	elog(ERROR, "failed to JIT: %s", fc_funcname);

	return NULL;
}

/* 返回 llvmjit_types.c 中变量的类型。这对于在普通 C 和与 JIT 相关的代码之间保持类型同步非常有用。 */
LLVMTypeRef
llvm_pg_var_type(const char *fc_varname)
{
	LLVMValueRef fc_v_srcvar;
	LLVMTypeRef fc_typ;

	/* 这将返回全局的 *指针* */
	fc_v_srcvar = LLVMGetNamedGlobal(llvm_types_module, fc_varname);
	if (!fc_v_srcvar)
		elog(ERROR, "variable %s not in llvmjit_types.c", fc_varname);

	fc_typ = LLVMGlobalGetValueType(fc_v_srcvar);

	return fc_typ;
}

/* 返回 llvmjit_types.c 中变量的函数类型。这对于在 C 和 JIT 代码之间保持函数类型同步非常有用。 */
LLVMTypeRef
llvm_pg_var_func_type(const char *fc_varname)
{
	LLVMValueRef fc_v_srcvar;
	LLVMTypeRef fc_typ;

	fc_v_srcvar = LLVMGetNamedFunction(llvm_types_module, fc_varname);
	if (!fc_v_srcvar)
		elog(ERROR, "function %s not in llvmjit_types.c", fc_varname);

	fc_typ = LLVMGetFunctionType(fc_v_srcvar);

	return fc_typ;
}

/* 返回 llvmjit_types.c 中引用的函数的声明，如果必要的话，将其添加到模块中。 * 这用于使通过 llvm_create_types() 发现的函数对于当前正在处理的模块可见。 */
LLVMValueRef llvm_pg_func(LLVMModuleRef fc_mod, const char *fc_funcname)
{
	LLVMValueRef fc_v_srcfn;
	LLVMValueRef fc_v_fn;

	/* 不要重复添加函数 */
	fc_v_fn = LLVMGetNamedFunction(fc_mod, fc_funcname);
	if (fc_v_fn)
		return fc_v_fn;

	fc_v_srcfn = LLVMGetNamedFunction(llvm_types_module, fc_funcname);

	if (!fc_v_srcfn)
		elog(ERROR, "function %s not in llvmjit_types.c", fc_funcname);

	fc_v_fn = LLVMAddFunction(fc_mod,
						   fc_funcname,
						   LLVMGetFunctionType(fc_v_srcfn));
	llvm_copy_attributes(fc_v_srcfn, fc_v_fn);

	return fc_v_fn;
}

/* 从一个函数复制属性到另一个函数，针对特定索引（索引可以引用返回值、函数和参数属性）。 */
static void fc_llvm_copy_attributes_at_index(LLVMValueRef fc_v_from, LLVMValueRef fc_v_to, uint32 fc_index)
{
	int			fc_num_attributes;
	LLVMAttributeRef *fc_attrs;

	fc_num_attributes = LLVMGetAttributeCountAtIndexPG(fc_v_from, fc_index);

	/*
	 * 不仅仅出于效率考虑：当调用具有 0 个属性的索引的
	 * LLVMGetAttributesAtIndex() 时，LLVM <= 3.9 会崩溃。
	 */
	if (fc_num_attributes == 0)
		return;

	fc_attrs = palloc(sizeof(LLVMAttributeRef) * fc_num_attributes);
	LLVMGetAttributesAtIndex(fc_v_from, fc_index, fc_attrs);

	for (int fc_attno = 0; fc_attno < fc_num_attributes; fc_attno++)
		LLVMAddAttributeAtIndex(fc_v_to, fc_index, fc_attrs[fc_attno]);

	pfree(fc_attrs);
}

/*
 * 从一个函数复制所有属性到另一个函数。即，函数、返回值和
 * 参数将被复制。
 */
void llvm_copy_attributes(LLVMValueRef fc_v_from, LLVMValueRef fc_v_to)
{
	uint32		fc_param_count;

	/* 复制函数属性 */
	fc_llvm_copy_attributes_at_index(fc_v_from, fc_v_to, LLVMAttributeFunctionIndex);

	if (LLVMGetTypeKind(LLVMGetFunctionReturnType(fc_v_to)) != LLVMVoidTypeKind)
	{
		/* 和返回值属性 */
		fc_llvm_copy_attributes_at_index(fc_v_from, fc_v_to, LLVMAttributeReturnIndex);
	}

	/* 和每个函数参数的属性 */
	fc_param_count = LLVMCountParams(fc_v_from);

	for (int fc_paramidx = 1; fc_paramidx <= fc_param_count; fc_paramidx++)
		fc_llvm_copy_attributes_at_index(fc_v_from, fc_v_to, fc_paramidx);
}

/*
 * 返回一个可调用的 LLVMValueRef 的 fcinfo。
 */
LLVMValueRef llvm_function_reference(LLVMJitContext *fc_context,
						LLVMBuilderRef fc_builder,
						LLVMModuleRef fc_mod,
						FunctionCallInfo fcinfo)
{
	char	   *fc_modname;
	char	   *fc_basename;
	char	   *fc_funcname;

	LLVMValueRef fc_v_fn;

	fmgr_symbol(fcinfo->flinfo->fn_oid, &fc_modname, &fc_basename);

	if (fc_modname != NULL && fc_basename != NULL)
	{
		/* 可加载库中的外部函数 */
		fc_funcname = psprintf("pgextern.%s.%s", fc_modname, fc_basename);
	}
	else if (fc_basename != NULL)
	{
		/* 内部函数 */
		fc_funcname = psprintf("%s", fc_basename);
	}
	else
	{
		/*
		 * 我们不知道如何处理的函数，返回指针。我们这样做是通过
		 * 创建一个包含指向函数的指针的全局常量。
		 * 使 IR 更加可读。
		 */
		LLVMValueRef fc_v_fn_addr;

		fc_funcname = psprintf("pgoidextern.%u",
							fcinfo->flinfo->fn_oid);
		fc_v_fn = LLVMGetNamedGlobal(fc_mod, fc_funcname);
		if (fc_v_fn != 0)
			return l_load(fc_builder, TypePGFunction, fc_v_fn, "");

		fc_v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction);

		fc_v_fn = LLVMAddGlobal(fc_mod, TypePGFunction, fc_funcname);
		LLVMSetInitializer(fc_v_fn, fc_v_fn_addr);
		LLVMSetGlobalConstant(fc_v_fn, true);
		LLVMSetLinkage(fc_v_fn, LLVMPrivateLinkage);
		LLVMSetUnnamedAddr(fc_v_fn, true);

		return l_load(fc_builder, TypePGFunction, fc_v_fn, "");
	}

	/* 检查函数是否已经添加 */
	fc_v_fn = LLVMGetNamedFunction(fc_mod, fc_funcname);
	if (fc_v_fn != 0)
		return fc_v_fn;

	fc_v_fn = LLVMAddFunction(fc_mod, fc_funcname, LLVMGetFunctionType(AttributeTemplate));

	return fc_v_fn;
}

/*
 * 使用上下文中设置的标志优化模块中的代码。
 */
static void fc_llvm_optimize_module(LLVMJitContext *fc_context, LLVMModuleRef fc_module)
{
#if LLVM_VERSION_MAJOR < 17
	LLVMPassManagerBuilderRef llvm_pmb;
	LLVMPassManagerRef llvm_mpm;
	LLVMPassManagerRef llvm_fpm;
	LLVMValueRef func;
	int			compile_optlevel;

	if (context->base.flags & PGJIT_OPT3)
		compile_optlevel = 3;
	else
		compile_optlevel = 0;

	/*
	 * 每次通过时都必须创建一个新的传递管理器生成器，因为
	 * 内联器有一些每个生成器的状态。否则只会在第一次
	 * 内联函数。
	 */
	llvm_pmb = LLVMPassManagerBuilderCreate();
	LLVMPassManagerBuilderSetOptLevel(llvm_pmb, compile_optlevel);
	llvm_fpm = LLVMCreateFunctionPassManagerForModule(module);

	if (context->base.flags & PGJIT_OPT3)
	{
		/* TODO: 未科学确定的阈值 */
		LLVMPassManagerBuilderUseInlinerWithThreshold(llvm_pmb, 512);
	}
	else
	{
		/* 我们在很大程度上依赖于 mem2reg，因此即使在 O0 情况下也会发出 */
		LLVMAddPromoteMemoryToRegisterPass(llvm_fpm);
	}

	LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm);

	/*
	 * 执行函数级别的优化。这可以移动到函数发出时，以少量
	 * 减少内存使用。
	 */
	LLVMInitializeFunctionPassManager(llvm_fpm);
	for (func = LLVMGetFirstFunction(context->module);
		 func != NULL;
		 func = LLVMGetNextFunction(func))
		LLVMRunFunctionPassManager(llvm_fpm, func);
	LLVMFinalizeFunctionPassManager(llvm_fpm);
	LLVMDisposePassManager(llvm_fpm);

	/*
	 * 执行模块级别的优化。即使在非优化情况下也这样做，因此
	 * 总是内联的函数等会被内联。这样做成本足够低。
	 */
	llvm_mpm = LLVMCreatePassManager();
	LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb,
													llvm_mpm);
	/* 始终使用始终内联器传递 */
	if (!(context->base.flags & PGJIT_OPT3))
		LLVMAddAlwaysInlinerPass(llvm_mpm);
	/* 如果进行内联，但没有昂贵的优化，则添加内联传递 */
	if (context->base.flags & PGJIT_INLINE
		&& !(context->base.flags & PGJIT_OPT3))
		LLVMAddFunctionInliningPass(llvm_mpm);
	LLVMRunPassManager(llvm_mpm, context->module);
	LLVMDisposePassManager(llvm_mpm);

	LLVMPassManagerBuilderDispose(llvm_pmb);
#else
	LLVMPassBuilderOptionsRef fc_options;
	LLVMErrorRef fc_err;
	const char *fc_passes;

	if (fc_context->base.flags & PGJIT_OPT3)
		fc_passes = "default<O3>";
	else
		fc_passes = "default<O0>,mem2reg";

	fc_options = LLVMCreatePassBuilderOptions();

#ifdef LLVM_PASS_DEBUG
	LLVMPassBuilderOptionsSetDebugLogging(fc_options, 1);
#endif

	LLVMPassBuilderOptionsSetInlinerThreshold(fc_options, 512);

	fc_err = LLVMRunPasses(fc_module, fc_passes, NULL, fc_options);

	if (fc_err)
		elog(ERROR, "failed to JIT module: %s", fc_llvm_error_message(fc_err));

	LLVMDisposePassBuilderOptions(fc_options);
#endif
}

/*
 * 发出当前待处理模块的代码。
 */
static void fc_llvm_compile_module(LLVMJitContext *fc_context)
{
	LLVMJitHandle *fc_handle;
	MemoryContext fc_oldcontext;
	instr_time	fc_starttime;
	instr_time	fc_endtime;
#if LLVM_VERSION_MAJOR > 11
	LLVMOrcLLJITRef fc_compile_orc;
#else
	LLVMOrcJITStackRef fc_compile_orc;
#endif

	if (fc_context->base.flags & PGJIT_OPT3)
		fc_compile_orc = llvm_opt3_orc;
	else
		fc_compile_orc = llvm_opt0_orc;

	/* 执行内联 */
	if (fc_context->base.flags & PGJIT_INLINE)
	{
		INSTR_TIME_SET_CURRENT(fc_starttime);
		llvm_inline(fc_context->module);
		INSTR_TIME_SET_CURRENT(fc_endtime);
		INSTR_TIME_ACCUM_DIFF(fc_context->base.instr.inlining_counter,
							  fc_endtime, fc_starttime);
	}

	if (jit_dump_bitcode)
	{
		char	   *fc_filename;

		fc_filename = psprintf("%u.%zu.bc",
							MyProcPid,
							fc_context->module_generation);
		LLVMWriteBitcodeToFile(fc_context->module, fc_filename);
		pfree(fc_filename);
	}


	/* 根据选择的优化设置进行优化 */
	INSTR_TIME_SET_CURRENT(fc_starttime);
	fc_llvm_optimize_module(fc_context, fc_context->module);
	INSTR_TIME_SET_CURRENT(fc_endtime);
	INSTR_TIME_ACCUM_DIFF(fc_context->base.instr.optimization_counter,
						  fc_endtime, fc_starttime);

	if (jit_dump_bitcode)
	{
		char	   *fc_filename;

		fc_filename = psprintf("%u.%zu.optimized.bc",
							MyProcPid,
							fc_context->module_generation);
		LLVMWriteBitcodeToFile(fc_context->module, fc_filename);
		pfree(fc_filename);
	}

	fc_handle = (LLVMJitHandle *)
		MemoryContextAlloc(TopMemoryContext, sizeof(LLVMJitHandle));

	/*
	 * 发出代码。请注意，这可能会根据优化
	 * 设置消耗明显资源，因为代码发出执行低级
	 * 指令合并/选择传递等。在没有优化的情况下，
	 * 使用更快的指令选择机制。
	 */
	INSTR_TIME_SET_CURRENT(fc_starttime);
#if LLVM_VERSION_MAJOR > 11
	{
		LLVMOrcThreadSafeModuleRef fc_ts_module;
		LLVMErrorRef fc_error;
		LLVMOrcJITDylibRef fc_jd = LLVMOrcLLJITGetMainJITDylib(fc_compile_orc);

		fc_ts_module = LLVMOrcCreateNewThreadSafeModule(fc_context->module, llvm_ts_context);

		fc_handle->lljit = fc_compile_orc;
		fc_handle->resource_tracker = LLVMOrcJITDylibCreateResourceTracker(fc_jd);

		/*
		 * 注意：这实际上并不发出代码。第一次
		 * 请求模块中定义的符号时会懒惰地发生。这意味着
		 * llvm_get_function() 也会考虑发出时间。
		 */

		fc_context->module = NULL; /* 将由 LLJIT 所拥有 */
		fc_error = LLVMOrcLLJITAddLLVMIRModuleWithRT(fc_compile_orc,
												  fc_handle->resource_tracker,
												  fc_ts_module);

		if (fc_error)
			elog(ERROR, "failed to JIT module: %s",
				 fc_llvm_error_message(fc_error));

		fc_handle->lljit = fc_compile_orc;

		/* LLVMOrcLLJITAddLLVMIRModuleWithRT 获取模块的所有权 */
	}
#elif LLVM_VERSION_MAJOR > 6
	{
		handle->stack = fc_compile_orc;
		if (LLVMOrcAddEagerlyCompiledIR(fc_compile_orc, &handle->orc_handle, context->module,
										llvm_resolve_symbol, NULL))
			elog(ERROR, "failed to JIT module");

		/* LLVMOrcAddEagerlyCompiledIR 获取模块的所有权 */
	}
#elif LLVM_VERSION_MAJOR > 4
	{
		LLVMSharedModuleRef smod;

		smod = LLVMOrcMakeSharedModule(context->module);
		handle->stack = fc_compile_orc;
		if (LLVMOrcAddEagerlyCompiledIR(fc_compile_orc, &handle->orc_handle, smod,
										llvm_resolve_symbol, NULL))
			elog(ERROR, "failed to JIT module");

		LLVMOrcDisposeSharedModuleRef(smod);
	}
#else							/* LLVM 4.0 和 3.9 */
	{
		handle->stack = fc_compile_orc;
		handle->orc_handle = LLVMOrcAddEagerlyCompiledIR(fc_compile_orc, context->module,
														 llvm_resolve_symbol, NULL);

		LLVMDisposeModule(context->module);
	}
#endif

	INSTR_TIME_SET_CURRENT(fc_endtime);
	INSTR_TIME_ACCUM_DIFF(fc_context->base.instr.emission_counter,
						  fc_endtime, fc_starttime);

	fc_context->module = NULL;
	fc_context->compiled = true;

	/* 记住发出代码以便清理和查找 */
	fc_oldcontext = MemoryContextSwitchTo(TopMemoryContext);
	fc_context->handles = lappend(fc_context->handles, fc_handle);
	MemoryContextSwitchTo(fc_oldcontext);

	ereport(DEBUG1,
			(errmsg_internal("time to inline: %.3fs, opt: %.3fs, emit: %.3fs",
							 INSTR_TIME_GET_DOUBLE(fc_context->base.instr.inlining_counter),
							 INSTR_TIME_GET_DOUBLE(fc_context->base.instr.optimization_counter),
							 INSTR_TIME_GET_DOUBLE(fc_context->base.instr.emission_counter)),
			 errhidestmt(true),
			 errhidecontext(true)));
}

/*
 * 每个会话的初始化。
 */
static void fc_llvm_session_initialize(void)
{
	MemoryContext fc_oldcontext;
	char	   *fc_error = NULL;
	char	   *fc_cpu = NULL;
	char	   *fc_features = NULL;
	LLVMTargetMachineRef fc_opt0_tm;
	LLVMTargetMachineRef fc_opt3_tm;

	if (llvm_session_initialized)
		return;

	fc_oldcontext = MemoryContextSwitchTo(TopMemoryContext);

	LLVMInitializeNativeTarget();
	LLVMInitializeNativeAsmPrinter();
	LLVMInitializeNativeAsmParser();

	if (llvm_context == NULL)
	{
		llvm_context = LLVMContextCreate();

		llvm_jit_context_in_use_count = 0;
		llvm_llvm_context_reuse_count = 0;
	}

	/*
	 * 当目标是 LLVM 15 时，关闭我们构建代码的上下文中的不透明指针。
	 * 我们对其他上下文（例如 llvm_ts_context）不需要这么做。
	 * 一旦生成 IR，它会携带必要的信息。
	 * 
	 * 对于16及以上，必须使用不透明指针，我们有特殊
	 * 代码来处理。
	 */
#if LLVM_VERSION_MAJOR == 15
	LLVMContextSetOpaquePointers(LLVMGetGlobalContext(), false);
#endif

	/*
	 * 早期同步类型，因为这也包括推断目标
	 * 三重。
	 */
	fc_llvm_create_types();

	/*
	 * 从加载的模块提取目标信息。
	 */
	fc_llvm_set_target();

	if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &fc_error) != 0)
	{
		elog(FATAL, "failed to query triple %s", fc_error);
	}

	/*
	 * 我们希望生成的代码使用所有可用的功能。因此
	 * 获取主机 CPU 字符串并检测当前 CPU 的特性。
	 * 后者是必要的，因为某些 CPU 架构默认启用
	 * 不是所有 CPU 都具备的功能（奇怪吧）。
	 */
	fc_cpu = LLVMGetHostCPUName();
	fc_features = LLVMGetHostCPUFeatures();
	elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
		 fc_cpu, fc_features);

	fc_opt0_tm =
		LLVMCreateTargetMachine(llvm_targetref, llvm_triple, fc_cpu, fc_features,
								LLVMCodeGenLevelNone,
								LLVMRelocDefault,
								LLVMCodeModelJITDefault);
	fc_opt3_tm =
		LLVMCreateTargetMachine(llvm_targetref, llvm_triple, fc_cpu, fc_features,
								LLVMCodeGenLevelAggressive,
								LLVMRelocDefault,
								LLVMCodeModelJITDefault);

	LLVMDisposeMessage(fc_cpu);
	fc_cpu = NULL;
	LLVMDisposeMessage(fc_features);
	fc_features = NULL;

	/* 强制主程序中的符号被加载 */
	LLVMLoadLibraryPermanently(NULL);

#if LLVM_VERSION_MAJOR > 11
	{
		llvm_ts_context = LLVMOrcCreateNewThreadSafeContext();

		llvm_opt0_orc = fc_llvm_create_jit_instance(fc_opt0_tm);
		fc_opt0_tm = 0;

		llvm_opt3_orc = fc_llvm_create_jit_instance(fc_opt3_tm);
		fc_opt3_tm = 0;
	}
#else							/* LLVM_VERSION_MAJOR > 11 */
	{
		llvm_opt0_orc = LLVMOrcCreateInstance(opt0_tm);
		llvm_opt3_orc = LLVMOrcCreateInstance(opt3_tm);

#if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
		if (jit_debugging_support)
		{
			LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener();

			LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
			LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
		}
#endif
#if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER
		if (jit_profiling_support)
		{
			LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener();

			LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l);
			LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l);
		}
#endif
	}
#endif							/* LLVM_VERSION_MAJOR > 11 */

	on_proc_exit(fc_llvm_shutdown, 0);

	llvm_session_initialized = true;

	MemoryContextSwitchTo(fc_oldcontext);
}

static void fc_llvm_shutdown(int fc_code, Datum fc_arg)
{
	/*
	 * 如果在致命的 out-of-memory 部分到达 llvm_shutdown()，
	 * 则在 LLVM 代码中发生了错误。回调进入
	 * LLVM 并不安全（这就是为什么抛出了 FATAL 错误）。
	 *
	 * 我们确实需要在其他关闭情况下关闭 LLVM，
	 * 否则例如，剖析数据将不会被写出。
	 */
	if (llvm_in_fatal_on_oom())
	{
		Assert(proc_exit_inprogress);
		return;
	}

	if (llvm_jit_context_in_use_count != 0)
		elog(PANIC, "LLVMJitContext in use count not 0 at exit (is %zu)",
			 llvm_jit_context_in_use_count);

#if LLVM_VERSION_MAJOR > 11
	{
		if (llvm_opt3_orc)
		{
			LLVMOrcDisposeLLJIT(llvm_opt3_orc);
			llvm_opt3_orc = NULL;
		}
		if (llvm_opt0_orc)
		{
			LLVMOrcDisposeLLJIT(llvm_opt0_orc);
			llvm_opt0_orc = NULL;
		}
		if (llvm_ts_context)
		{
			LLVMOrcDisposeThreadSafeContext(llvm_ts_context);
			llvm_ts_context = NULL;
		}
	}
#else							/* LLVM_VERSION_MAJOR > 11 */
	{
		/* 取消注册剖析支持，需要刷新才能有效 */

		if (llvm_opt3_orc)
		{
#if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
			if (jit_profiling_support)
				LLVMOrcUnregisterPerf(llvm_opt3_orc);
#endif
			LLVMOrcDisposeInstance(llvm_opt3_orc);
			llvm_opt3_orc = NULL;
		}

		if (llvm_opt0_orc)
		{
#if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF
			if (jit_profiling_support)
				LLVMOrcUnregisterPerf(llvm_opt0_orc);
#endif
			LLVMOrcDisposeInstance(llvm_opt0_orc);
			llvm_opt0_orc = NULL;
		}
	}
#endif							/* LLVM_VERSION_MAJOR > 11 */
}

/* llvm_create_types 的辅助函数，返回函数的返回类型 */
static LLVMTypeRef
fc_load_return_type(LLVMModuleRef fc_mod, const char *fc_name)
{
	LLVMValueRef fc_value;
	LLVMTypeRef fc_typ;

	/* 这将返回一个指向函数的 *指针* */
	fc_value = LLVMGetNamedFunction(fc_mod, fc_name);
	if (!fc_value)
		elog(ERROR, "function %s is unknown", fc_name);

	fc_typ = LLVMGetFunctionReturnType(fc_value); /* 在 llvmjit_wrap.cpp 中 */

	return fc_typ;
}

/*
 * 从 clang 生成的文件加载三元组和布局，以确保我们兼容。
 */
static void fc_llvm_set_target(void)
{
	if (!llvm_types_module)
		elog(ERROR, "failed to extract target information, llvmjit_types.c not loaded");

	if (llvm_triple == NULL)
		llvm_triple = pstrdup(LLVMGetTarget(llvm_types_module));

	if (llvm_layout == NULL)
		llvm_layout = pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
}

/*
 * 从 llvmjit_types.c 加载所需的信息、类型、函数签名
 * 并将其在全局变量中可用。
 *
 * 这些全局变量在发出代码时会被使用。
 */
static void fc_llvm_create_types(void)
{
	char		fc_path[MAXPGPATH];
	LLVMMemoryBufferRef fc_buf;
	char	   *fc_msg;

	snprintf(fc_path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");

	/* 打开文件 */
	if (LLVMCreateMemoryBufferWithContentsOfFile(fc_path, &fc_buf, &fc_msg))
	{
		elog(ERROR, "LLVMCreateMemoryBufferWithContentsOfFile(%s) failed: %s",
			 fc_path, fc_msg);
	}

	/* 急切地加载内容，所有内容都将需要 */
	if (LLVMParseBitcodeInContext2(llvm_context, fc_buf, &llvm_types_module))
	{
		elog(ERROR, "LLVMParseBitcodeInContext2 of %s failed", fc_path);
	}
	LLVMDisposeMemoryBuffer(fc_buf);

	TypeSizeT = llvm_pg_var_type("TypeSizeT");
	TypeParamBool = fc_load_return_type(llvm_types_module, "FunctionReturningBool");
	TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
	TypePGFunction = llvm_pg_var_type("TypePGFunction");
	StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
	StructExprContext = llvm_pg_var_type("StructExprContext");
	StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
	StructExprState = llvm_pg_var_type("StructExprState");
	StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
	StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
	StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
	StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
	StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
	StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
	StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
	StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
	StructAggState = llvm_pg_var_type("StructAggState");
	StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
	StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
	StructPlanState = llvm_pg_var_type("StructPlanState");
	StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");

	AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
	ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
	ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
}

/*
 * 将符号分割为模块 / 函数部分。如果函数位于
 * 主程序（或外部库）中，*modname 将为 NULL。
 */
void llvm_split_symbol_name(const char *fc_name, char **fc_modname, char **fc_funcname)
{
	*fc_modname = NULL;
	*fc_funcname = NULL;

	/*
	 * 模块函数名称为 pgextern.$module.$funcname
	 */
	if (strncmp(fc_name, "pgextern.", strlen("pgextern.")) == 0)
	{
		/*
		 * 符号名称不能包含 .，因此我们可以根据
		 * 第一次和最后一次出现进行分割。
		 */
		*fc_funcname = rindex(fc_name, '.');
		(*fc_funcname)++;			/* 跳过 . */

		*fc_modname = pnstrdup(fc_name + strlen("pgextern."),
							*fc_funcname - fc_name - strlen("pgextern.") - 1);
		Assert(fc_funcname);

		*fc_funcname = pstrdup(*fc_funcname);
	}
	else
	{
		*fc_modname = NULL;
		*fc_funcname = pstrdup(fc_name);
	}
}

/*
 * 尝试解析符号，以便 LLVM 可以发出对它的引用。
 */
static uint64_t
fc_llvm_resolve_symbol(const char *fc_symname, void *fc_ctx)
{
	uintptr_t	fc_addr;
	char	   *fc_funcname;
	char	   *fc_modname;

	/*
	 * macOS 为所有对象级符号添加下划线前缀。但无论是
	 * dlsym() 还是 PG 的内联器都不期望这样。因此撤销。
	 */
#if defined(__darwin__)
	if (symname[0] != '_')
		elog(ERROR, "expected prefixed symbol name, but got \"%s\"", symname);
	symname++;
#endif

	llvm_split_symbol_name(fc_symname, &fc_modname, &fc_funcname);

	/* 没有解析为名称的函数不应该到达这里 */
	Assert(fc_funcname);

	if (fc_modname)
		fc_addr = (uintptr_t) load_external_function(fc_modname, fc_funcname,
												  true, NULL);
	else
		fc_addr = (uintptr_t) LLVMSearchForAddressOfSymbol(fc_symname);

	pfree(fc_funcname);
	if (fc_modname)
		pfree(fc_modname);

	/* 让 LLVM 报错 - 这不应该发生 */
	if (!fc_addr)
		elog(WARNING, "failed to resolve name %s", fc_symname);

	return (uint64_t) fc_addr;
}

#if LLVM_VERSION_MAJOR > 11

static LLVMErrorRef
fc_llvm_resolve_symbols(LLVMOrcDefinitionGeneratorRef fc_GeneratorObj, void *fc_Ctx,
					 LLVMOrcLookupStateRef * fc_LookupState, LLVMOrcLookupKind fc_Kind,
					 LLVMOrcJITDylibRef fc_JD, LLVMOrcJITDylibLookupFlags fc_JDLookupFlags,
					 LLVMOrcCLookupSet fc_LookupSet, size_t fc_LookupSetSize)
{
#if LLVM_VERSION_MAJOR > 14
	LLVMOrcCSymbolMapPairs fc_symbols = palloc0(sizeof(LLVMOrcCSymbolMapPair) * fc_LookupSetSize);
#else
	LLVMOrcCSymbolMapPairs symbols = palloc0(sizeof(LLVMJITCSymbolMapPair) * LookupSetSize);
#endif
	LLVMErrorRef fc_error;
	LLVMOrcMaterializationUnitRef fc_mu;

	for (int fc_i = 0; fc_i < fc_LookupSetSize; fc_i++)
	{
		const char *fc_name = LLVMOrcSymbolStringPoolEntryStr(fc_LookupSet[fc_i].Name);

#if LLVM_VERSION_MAJOR > 12
		LLVMOrcRetainSymbolStringPoolEntry(fc_LookupSet[fc_i].Name);
#endif
		fc_symbols[fc_i].Name = fc_LookupSet[fc_i].Name;
		fc_symbols[fc_i].Sym.Address = fc_llvm_resolve_symbol(fc_name, NULL);
		fc_symbols[fc_i].Sym.Flags.GenericFlags = LLVMJITSymbolGenericFlagsExported;
	}

	fc_mu = LLVMOrcAbsoluteSymbols(fc_symbols, fc_LookupSetSize);
	fc_error = LLVMOrcJITDylibDefine(fc_JD, fc_mu);
	if (fc_error != LLVMErrorSuccess)
		LLVMOrcDisposeMaterializationUnit(fc_mu);

	pfree(fc_symbols);

	return fc_error;
}

/*
 * 我们不能通过 LLVM 抛出错误（至少不会导致 FATAL），
 * 所以这里仅使用 WARNING。这没问题，因为错误在
 * 顶层动作中也被报告（详细信息较少），而且可能会有多次
 * 带详细信息的错误调用。
 *
 * 这在正常操作期间并不常见，但在符号解析破坏等情况下会发生。
 * 所以仅使用 elog(WARNING) 就可以了。
 */
static void fc_llvm_log_jit_error(void *fc_ctx, LLVMErrorRef fc_error)
{
	elog(WARNING, "error during JITing: %s",
		 fc_llvm_error_message(fc_error));
}

/*
 * 创建我们自己的对象层，以便可以添加事件监听器。
 */
static LLVMOrcObjectLayerRef
fc_llvm_create_object_layer(void *fc_Ctx, LLVMOrcExecutionSessionRef fc_ES, const char *fc_Triple)
{
#ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER
	LLVMOrcObjectLayerRef fc_objlayer =
		LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(fc_ES);
#else
	LLVMOrcObjectLayerRef fc_objlayer =
		LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(fc_ES);
#endif

#if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
	if (jit_debugging_support)
	{
		LLVMJITEventListenerRef fc_l = LLVMCreateGDBRegistrationListener();

		LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(fc_objlayer, fc_l);
	}
#endif

#if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER
	if (jit_profiling_support)
	{
		LLVMJITEventListenerRef fc_l = LLVMCreatePerfJITEventListener();

		LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(fc_objlayer, fc_l);
	}
#endif

	return fc_objlayer;
}

/*
 * 创建 LLJIT 实例，使用传入的目标机器。注意，
 * 此后的目标机器由 LLJIT 实例拥有。
 */
static LLVMOrcLLJITRef
fc_llvm_create_jit_instance(LLVMTargetMachineRef fc_tm)
{
	LLVMOrcLLJITRef fc_lljit;
	LLVMOrcJITTargetMachineBuilderRef fc_tm_builder;
	LLVMOrcLLJITBuilderRef fc_lljit_builder;
	LLVMErrorRef fc_error;
	LLVMOrcDefinitionGeneratorRef fc_main_gen;
	LLVMOrcDefinitionGeneratorRef fc_ref_gen;

	fc_lljit_builder = LLVMOrcCreateLLJITBuilder();
	fc_tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(fc_tm);
	LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(fc_lljit_builder, fc_tm_builder);

	LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(fc_lljit_builder,
													fc_llvm_create_object_layer,
													NULL);

	fc_error = LLVMOrcCreateLLJIT(&fc_lljit, fc_lljit_builder);
	if (fc_error)
		elog(ERROR, "failed to create lljit instance: %s",
			 fc_llvm_error_message(fc_error));

	LLVMOrcExecutionSessionSetErrorReporter(LLVMOrcLLJITGetExecutionSession(fc_lljit),
											fc_llvm_log_jit_error, NULL);

	/*
	 * 对于已经加载的 postgres 二进制文件 /
	 * 库中的符号的符号解析支持。
	 */
	fc_error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&fc_main_gen,
																 LLVMOrcLLJITGetGlobalPrefix(fc_lljit),
																 0, NULL);
	if (fc_error)
		elog(ERROR, "failed to create generator: %s",
			 fc_llvm_error_message(fc_error));
	LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(fc_lljit), fc_main_gen);

	/*
	 * 对于“特殊”函数的符号解析支持，例如调用
	 * SQL 可调用函数。
	 */
#if LLVM_VERSION_MAJOR > 14
	fc_ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(fc_llvm_resolve_symbols, NULL, NULL);
#else
	ref_gen = LLVMOrcCreateCustomCAPIDefinitionGenerator(llvm_resolve_symbols, NULL);
#endif
	LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(fc_lljit), fc_ref_gen);

	return fc_lljit;
}

static char * fc_llvm_error_message(LLVMErrorRef fc_error)
{
	char	   *fc_orig = LLVMGetErrorMessage(fc_error);
	char	   *fc_msg = pstrdup(fc_orig);

	LLVMDisposeErrorMessage(fc_orig);

	return fc_msg;
}

#endif							/* LLVM_VERSION_MAJOR > 11 */
